home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / lib / firefox-3.5.5 / components / fuelApplication.js < prev    next >
Text File  |  2009-11-09  |  39KB  |  1,455 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is FUEL.
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla Corporation.
  17.  * Portions created by the Initial Developer are Copyright (C) 2006
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *  Mark Finkle <mfinkle@mozilla.com> (Original Author)
  22.  *  John Resig  <jresig@mozilla.com> (Original Author)
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38. const Ci = Components.interfaces;
  39. const Cc = Components.classes;
  40.  
  41. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  42.  
  43. //=================================================
  44. // Singleton that holds services and utilities
  45. var Utilities = {
  46.   _bookmarks : null,
  47.   get bookmarks() {
  48.     if (!this._bookmarks) {
  49.       this._bookmarks = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
  50.                         getService(Ci.nsINavBookmarksService);
  51.     }
  52.     return this._bookmarks;
  53.   },
  54.  
  55.   _livemarks : null,
  56.   get livemarks() {
  57.     if (!this._livemarks) {
  58.       this._livemarks = Cc["@mozilla.org/browser/livemark-service;2"].
  59.                         getService(Ci.nsILivemarkService);
  60.     }
  61.     return this._livemarks;
  62.   },
  63.  
  64.   _annotations : null,
  65.   get annotations() {
  66.     if (!this._annotations) {
  67.       this._annotations = Cc["@mozilla.org/browser/annotation-service;1"].
  68.                           getService(Ci.nsIAnnotationService);
  69.     }
  70.     return this._annotations;
  71.   },
  72.  
  73.   _history : null,
  74.   get history() {
  75.     if (!this._history) {
  76.       this._history = Cc["@mozilla.org/browser/nav-history-service;1"].
  77.                       getService(Ci.nsINavHistoryService);
  78.     }
  79.     return this._history;
  80.   },
  81.  
  82.   _windowMediator : null,
  83.   get windowMediator() {
  84.     if (!this._windowMediator) {
  85.       this._windowMediator = Cc["@mozilla.org/appshell/window-mediator;1"].
  86.                              getService(Ci.nsIWindowMediator);
  87.     }
  88.     return this._windowMediator;
  89.   },
  90.  
  91.   makeURI : function(aSpec) {
  92.     if (!aSpec)
  93.       return null;
  94.     var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
  95.     return ios.newURI(aSpec, null, null);
  96.   },
  97.  
  98.   free : function() {
  99.     this._bookmarks = null;
  100.     this._livemarks = null;
  101.     this._annotations = null;
  102.     this._history = null;
  103.     this._windowMediator = null;
  104.   }
  105. };
  106.  
  107.  
  108. //=================================================
  109. // Window implementation
  110. function Window(aWindow) {
  111.   this._window = aWindow;
  112.   this._tabbrowser = aWindow.getBrowser();
  113.   this._events = new Events();
  114.   this._cleanup = {};
  115.  
  116.   this._watch("TabOpen");
  117.   this._watch("TabMove");
  118.   this._watch("TabClose");
  119.   this._watch("TabSelect");
  120.  
  121.   var self = this;
  122.   gShutdown.push(function() { self._shutdown(); });
  123. }
  124.  
  125. Window.prototype = {
  126.   get events() {
  127.     return this._events;
  128.   },
  129.  
  130.   /*
  131.    * Helper used to setup event handlers on the XBL element. Note that the events
  132.    * are actually dispatched to tabs, so we capture them.
  133.    */
  134.   _watch : function win_watch(aType) {
  135.     var self = this;
  136.     this._tabbrowser.addEventListener(aType,
  137.       this._cleanup[aType] = function(e){ self._event(e); },
  138.       true);
  139.   },
  140.  
  141.   /*
  142.    * Helper event callback used to redirect events made on the XBL element
  143.    */
  144.   _event : function win_event(aEvent) {
  145.     this._events.dispatch(aEvent.type, new BrowserTab(this, aEvent.originalTarget.linkedBrowser));
  146.   },
  147.  
  148.   get tabs() {
  149.     var tabs = [];
  150.     var browsers = this._tabbrowser.browsers;
  151.  
  152.     for (var i=0; i<browsers.length; i++)
  153.       tabs.push(new BrowserTab(this, browsers[i]));
  154.     return tabs;
  155.   },
  156.  
  157.   get activeTab() {
  158.     return new BrowserTab(this, this._tabbrowser.selectedBrowser);
  159.   },
  160.  
  161.   open : function win_open(aURI) {
  162.     return new BrowserTab(this, this._tabbrowser.addTab(aURI.spec).linkedBrowser);
  163.   },
  164.  
  165.   _shutdown : function win_shutdown() {
  166.     for (var type in this._cleanup)
  167.       this._tabbrowser.removeEventListener(type, this._cleanup[type], true);
  168.     this._cleanup = null;
  169.  
  170.     this._window = null;
  171.     this._tabbrowser = null;
  172.     this._events = null;
  173.   },
  174.  
  175.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIWindow])
  176. };
  177.  
  178.  
  179. //=================================================
  180. // BrowserTab implementation
  181. function BrowserTab(aFUELWindow, aBrowser) {
  182.   this._window = aFUELWindow;
  183.   this._tabbrowser = aFUELWindow._tabbrowser;
  184.   this._browser = aBrowser;
  185.   this._events = new Events();
  186.   this._cleanup = {};
  187.  
  188.   this._watch("load");
  189.  
  190.   var self = this;
  191.   gShutdown.push(function() { self._shutdown(); });
  192. }
  193.  
  194. BrowserTab.prototype = {
  195.   get uri() {
  196.     return this._browser.currentURI;
  197.   },
  198.  
  199.   get index() {
  200.     var tabs = this._tabbrowser.mTabs;
  201.     for (var i=0; i<tabs.length; i++) {
  202.       if (tabs[i].linkedBrowser == this._browser)
  203.         return i;
  204.     }
  205.     return -1;
  206.   },
  207.  
  208.   get events() {
  209.     return this._events;
  210.   },
  211.  
  212.   get window() {
  213.     return this._window;
  214.   },
  215.  
  216.   get document() {
  217.     return this._browser.contentDocument;
  218.   },
  219.  
  220.   /*
  221.    * Helper used to setup event handlers on the XBL element
  222.    */
  223.   _watch : function bt_watch(aType) {
  224.     var self = this;
  225.     this._browser.addEventListener(aType,
  226.       this._cleanup[aType] = function(e){ self._event(e); },
  227.       true);
  228.   },
  229.  
  230.   /*
  231.    * Helper event callback used to redirect events made on the XBL element
  232.    */
  233.   _event : function bt_event(aEvent) {
  234.     if (aEvent.type == "load") {
  235.       if (!(aEvent.originalTarget instanceof Ci.nsIDOMHTMLDocument))
  236.         return;
  237.  
  238.       if (aEvent.originalTarget.defaultView instanceof Ci.nsIDOMWindowInternal &&
  239.           aEvent.originalTarget.defaultView.frameElement)
  240.         return;
  241.     }
  242.  
  243.     this._events.dispatch(aEvent.type, this);
  244.   },
  245.  
  246.   /*
  247.    * Helper used to determine the index offset of the browsertab
  248.    */
  249.   _getTab : function bt_gettab() {
  250.     var tabs = this._tabbrowser.mTabs;
  251.     return tabs[this.index] || null;
  252.   },
  253.  
  254.   load : function bt_load(aURI) {
  255.     this._browser.loadURI(aURI.spec, null, null);
  256.   },
  257.  
  258.   focus : function bt_focus() {
  259.     this._tabbrowser.selectedTab = this._getTab();
  260.     this._tabbrowser.focus();
  261.   },
  262.  
  263.   close : function bt_close() {
  264.     this._tabbrowser.removeTab(this._getTab());
  265.   },
  266.  
  267.   moveBefore : function bt_movebefore(aBefore) {
  268.     this._tabbrowser.moveTabTo(this._getTab(), aBefore.index);
  269.   },
  270.  
  271.   moveToEnd : function bt_moveend() {
  272.     this._tabbrowser.moveTabTo(this._getTab(), this._tabbrowser.browsers.length);
  273.   },
  274.  
  275.   _shutdown : function bt_shutdown() {
  276.     for (var type in this._cleanup)
  277.       this._browser.removeEventListener(type, this._cleanup[type], true);
  278.     this._cleanup = null;
  279.  
  280.     this._window = null;
  281.     this._tabbrowser = null;
  282.     this._browser = null;
  283.     this._events = null;
  284.   },
  285.  
  286.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBrowserTab])
  287. };
  288.  
  289.  
  290. //=================================================
  291. // Annotations implementation
  292. function Annotations(aId) {
  293.   this._id = aId;
  294. }
  295.  
  296. Annotations.prototype = {
  297.   get names() {
  298.     return Utilities.annotations.getItemAnnotationNames(this._id, {});
  299.   },
  300.  
  301.   has : function ann_has(aName) {
  302.     return Utilities.annotations.itemHasAnnotation(this._id, aName);
  303.   },
  304.  
  305.   get : function(aName) {
  306.     if (this.has(aName))
  307.       return Utilities.annotations.getItemAnnotation(this._id, aName);
  308.     return null;
  309.   },
  310.  
  311.   set : function(aName, aValue, aExpiration) {
  312.     Utilities.annotations.setItemAnnotation(this._id, aName, aValue, 0, aExpiration);
  313.   },
  314.  
  315.   remove : function ann_remove(aName) {
  316.     if (aName)
  317.       Utilities.annotations.removeItemAnnotation(this._id, aName);
  318.   },
  319.  
  320.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIAnnotations])
  321. };
  322.  
  323.  
  324. //=================================================
  325. // Bookmark implementation
  326. function Bookmark(aId, aParent, aType) {
  327.   this._id = aId;
  328.   this._parent = aParent;
  329.   this._type = aType || "bookmark";
  330.   this._annotations = new Annotations(this._id);
  331.   this._events = new Events();
  332.  
  333.   Utilities.bookmarks.addObserver(this, false);
  334.  
  335.   var self = this;
  336.   gShutdown.push(function() { self._shutdown(); });
  337. }
  338.  
  339. Bookmark.prototype = {
  340.   _shutdown : function bm_shutdown() {
  341.     this._annotations = null;
  342.     this._events = null;
  343.  
  344.     Utilities.bookmarks.removeObserver(this);
  345.   },
  346.  
  347.   get id() {
  348.     return this._id;
  349.   },
  350.  
  351.   get title() {
  352.     return Utilities.bookmarks.getItemTitle(this._id);
  353.   },
  354.  
  355.   set title(aTitle) {
  356.     Utilities.bookmarks.setItemTitle(this._id, aTitle);
  357.   },
  358.  
  359.   get uri() {
  360.     return Utilities.bookmarks.getBookmarkURI(this._id);
  361.   },
  362.  
  363.   set uri(aURI) {
  364.     return Utilities.bookmarks.changeBookmarkURI(this._id, aURI);
  365.   },
  366.  
  367.   get description() {
  368.     return this._annotations.get("bookmarkProperties/description");
  369.   },
  370.  
  371.   set description(aDesc) {
  372.     this._annotations.set("bookmarkProperties/description", aDesc, Ci.nsIAnnotationService.EXPIRE_NEVER);
  373.   },
  374.  
  375.   get keyword() {
  376.     return Utilities.bookmarks.getKeywordForBookmark(this._id);
  377.   },
  378.  
  379.   set keyword(aKeyword) {
  380.     Utilities.bookmarks.setKeywordForBookmark(this._id, aKeyword);
  381.   },
  382.  
  383.   get type() {
  384.     return this._type;
  385.   },
  386.  
  387.   get parent() {
  388.     return this._parent;
  389.   },
  390.  
  391.   set parent(aFolder) {
  392.     Utilities.bookmarks.moveItem(this._id, aFolder.id, Utilities.bookmarks.DEFAULT_INDEX);
  393.     // this._parent is updated in onItemMoved
  394.   },
  395.  
  396.   get annotations() {
  397.     return this._annotations;
  398.   },
  399.  
  400.   get events() {
  401.     return this._events;
  402.   },
  403.  
  404.   remove : function bm_remove() {
  405.     Utilities.bookmarks.removeItem(this._id);
  406.   },
  407.  
  408.   // observer
  409.   onBeginUpdateBatch : function bm_obub() {
  410.   },
  411.  
  412.   onEndUpdateBatch : function bm_oeub() {
  413.   },
  414.  
  415.   onItemAdded : function bm_oia(aId, aFolder, aIndex) {
  416.     // bookmark object doesn't exist at this point
  417.   },
  418.  
  419.   onItemRemoved : function bm_oir(aId, aFolder, aIndex) {
  420.     if (this._id == aId)
  421.       this._events.dispatch("remove", aId);
  422.   },
  423.  
  424.   onItemChanged : function bm_oic(aId, aProperty, aIsAnnotationProperty, aValue) {
  425.     if (this._id == aId)
  426.       this._events.dispatch("change", aProperty);
  427.   },
  428.  
  429.   onItemVisited: function bm_oiv(aId, aVisitID, aTime) {
  430.   },
  431.  
  432.   onItemMoved: function bm_oim(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
  433.     if (this._id == aId) {
  434.       this._parent = new BookmarkFolder(aNewParent, Utilities.bookmarks.getFolderIdForItem(aNewParent));
  435.       this._events.dispatch("move", aId);
  436.     }
  437.   },
  438.  
  439.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBookmark, Ci.nsINavBookmarkObserver])
  440. };
  441.  
  442.  
  443. //=================================================
  444. // BookmarkFolder implementation
  445. function BookmarkFolder(aId, aParent) {
  446.   this._id = aId;
  447.   this._parent = aParent;
  448.   this._annotations = new Annotations(this._id);
  449.   this._events = new Events();
  450.  
  451.   Utilities.bookmarks.addObserver(this, false);
  452.  
  453.   var self = this;
  454.   gShutdown.push(function() { self._shutdown(); });
  455. }
  456.  
  457. BookmarkFolder.prototype = {
  458.   _shutdown : function bmf_shutdown() {
  459.     this._annotations = null;
  460.     this._events = null;
  461.  
  462.     Utilities.bookmarks.removeObserver(this);
  463.   },
  464.  
  465.   get id() {
  466.     return this._id;
  467.   },
  468.  
  469.   get title() {
  470.     return Utilities.bookmarks.getItemTitle(this._id);
  471.   },
  472.  
  473.   set title(aTitle) {
  474.     Utilities.bookmarks.setItemTitle(this._id, aTitle);
  475.   },
  476.  
  477.   get description() {
  478.     return this._annotations.get("bookmarkProperties/description");
  479.   },
  480.  
  481.   set description(aDesc) {
  482.     this._annotations.set("bookmarkProperties/description", aDesc, Ci.nsIAnnotationService.EXPIRE_NEVER);
  483.   },
  484.  
  485.   get type() {
  486.     return "folder";
  487.   },
  488.  
  489.   get parent() {
  490.     return this._parent;
  491.   },
  492.  
  493.   set parent(aFolder) {
  494.     Utilities.bookmarks.moveItem(this._id, aFolder.id, Utilities.bookmarks.DEFAULT_INDEX);
  495.     // this._parent is updated in onItemMoved
  496.   },
  497.  
  498.   get annotations() {
  499.     return this._annotations;
  500.   },
  501.  
  502.   get events() {
  503.     return this._events;
  504.   },
  505.  
  506.   get children() {
  507.     var items = [];
  508.  
  509.     var options = Utilities.history.getNewQueryOptions();
  510.     var query = Utilities.history.getNewQuery();
  511.     query.setFolders([this._id], 1);
  512.     var result = Utilities.history.executeQuery(query, options);
  513.     var rootNode = result.root;
  514.     rootNode.containerOpen = true;
  515.     var cc = rootNode.childCount;
  516.     for (var i=0; i<cc; ++i) {
  517.       var node = rootNode.getChild(i);
  518.       if (node.type == node.RESULT_TYPE_FOLDER) {
  519.         var folder = new BookmarkFolder(node.itemId, this._id);
  520.         items.push(folder);
  521.       }
  522.       else if (node.type == node.RESULT_TYPE_SEPARATOR) {
  523.         var separator = new Bookmark(node.itemId, this._id, "separator");
  524.         items.push(separator);
  525.       }
  526.       else {
  527.         var bookmark = new Bookmark(node.itemId, this._id, "bookmark");
  528.         items.push(bookmark);
  529.       }
  530.     }
  531.     rootNode.containerOpen = false;
  532.  
  533.     return items;
  534.   },
  535.  
  536.   addBookmark : function bmf_addbm(aTitle, aUri) {
  537.     var newBookmarkID = Utilities.bookmarks.insertBookmark(this._id, aUri, Utilities.bookmarks.DEFAULT_INDEX, aTitle);
  538.     var newBookmark = new Bookmark(newBookmarkID, this, "bookmark");
  539.     return newBookmark;
  540.   },
  541.  
  542.   addSeparator : function bmf_addsep() {
  543.     var newBookmarkID = Utilities.bookmarks.insertSeparator(this._id, Utilities.bookmarks.DEFAULT_INDEX);
  544.     var newBookmark = new Bookmark(newBookmarkID, this, "separator");
  545.     return newBookmark;
  546.   },
  547.  
  548.   addFolder : function bmf_addfolder(aTitle) {
  549.     var newFolderID = Utilities.bookmarks.createFolder(this._id, aTitle, Utilities.bookmarks.DEFAULT_INDEX);
  550.     var newFolder = new BookmarkFolder(newFolderID, this);
  551.     return newFolder;
  552.   },
  553.  
  554.   remove : function bmf_remove() {
  555.     Utilities.bookmarks.removeFolder(this._id);
  556.   },
  557.  
  558.   // observer
  559.   onBeginUpdateBatch : function bmf_obub() {
  560.   },
  561.  
  562.   onEndUpdateBatch : function bmf_oeub() {
  563.   },
  564.  
  565.   onItemAdded : function bmf_oia(aId, aFolder, aIndex) {
  566.     // handle root folder events
  567.     if (!this._parent)
  568.       this._events.dispatch("add", aId);
  569.  
  570.     // handle this folder events
  571.     if (this._id == aFolder)
  572.       this._events.dispatch("addchild", aId);
  573.   },
  574.  
  575.   onItemRemoved : function bmf_oir(aId, aFolder, aIndex) {
  576.     // handle root folder events
  577.     if (!this._parent || this._id == aId)
  578.       this._events.dispatch("remove", aId);
  579.  
  580.     // handle this folder events
  581.     if (this._id == aFolder)
  582.       this._events.dispatch("removechild", aId);
  583.   },
  584.  
  585.   onItemChanged : function bmf_oic(aId, aProperty, aIsAnnotationProperty, aValue) {
  586.     // handle root folder and this folder events
  587.     if (!this._parent || this._id == aId)
  588.       this._events.dispatch("change", aProperty);
  589.   },
  590.  
  591.   onItemVisited: function bmf_oiv(aId, aVisitID, aTime) {
  592.   },
  593.  
  594.   onItemMoved: function bmf_oim(aId, aOldParent, aOldIndex, aNewParent, aNewIndex) {
  595.     // handle this folder event, root folder cannot be moved
  596.     if (this._id == aId) {
  597.       this._parent = new BookmarkFolder(aNewParent, Utilities.bookmarks.getFolderIdForItem(aNewParent));
  598.       this._events.dispatch("move", aId);
  599.     }
  600.   },
  601.  
  602.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBookmarkFolder, Ci.nsINavBookmarkObserver])
  603. };
  604.  
  605. //=================================================
  606. // BookmarkRoots implementation
  607. function BookmarkRoots() {
  608.   var self = this;
  609.   gShutdown.push(function() { self._shutdown(); });
  610. }
  611.  
  612. BookmarkRoots.prototype = {
  613.   _shutdown : function bmr_shutdown() {
  614.     this._menu = null;
  615.     this._toolbar = null;
  616.     this._tags = null;
  617.     this._unfiled = null;
  618.   },
  619.  
  620.   get menu() {
  621.     if (!this._menu)
  622.       this._menu = new BookmarkFolder(Utilities.bookmarks.bookmarksMenuFolder, null);
  623.  
  624.     return this._menu;
  625.   },
  626.  
  627.   get toolbar() {
  628.     if (!this._toolbar)
  629.       this._toolbar = new BookmarkFolder(Utilities.bookmarks.toolbarFolder, null);
  630.  
  631.     return this._toolbar;
  632.   },
  633.  
  634.   get tags() {
  635.     if (!this._tags)
  636.       this._tags = new BookmarkFolder(Utilities.bookmarks.tagsFolder, null);
  637.  
  638.     return this._tags;
  639.   },
  640.  
  641.   get unfiled() {
  642.     if (!this._unfiled)
  643.       this._unfiled = new BookmarkFolder(Utilities.bookmarks.unfiledBookmarksFolder, null);
  644.  
  645.     return this._unfiled;
  646.   },
  647.  
  648.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIBookmarkRoots])
  649. };
  650.  
  651.  
  652. //=================================================
  653. // Factory - Treat Application as a singleton
  654. // XXX This is required, because we're registered for the 'JavaScript global
  655. // privileged property' category, whose handler always calls createInstance.
  656. // See bug 386535.
  657. var gSingleton = null;
  658. var ApplicationFactory = {
  659.   createInstance: function af_ci(aOuter, aIID) {
  660.     if (aOuter != null)
  661.       throw Components.results.NS_ERROR_NO_AGGREGATION;
  662.  
  663.     if (gSingleton == null) {
  664.       gSingleton = new Application();
  665.     }
  666.  
  667.     return gSingleton.QueryInterface(aIID);
  668.   }
  669. };
  670.  
  671.  
  672.  
  673. //=================================================
  674. // Application constructor
  675. function Application() {
  676.   this.initToolkitHelpers();
  677.   this._bookmarks = null;
  678. }
  679.  
  680. //=================================================
  681. // Application implementation
  682. Application.prototype = {
  683.   // for nsIClassInfo + XPCOMUtils
  684.   classDescription: "Application",
  685.   classID:          Components.ID("fe74cf80-aa2d-11db-abbd-0800200c9a66"),
  686.   contractID:       "@mozilla.org/fuel/application;1",
  687.  
  688.   // redefine the default factory for XPCOMUtils
  689.   _xpcom_factory: ApplicationFactory,
  690.  
  691.   // for nsISupports
  692.   QueryInterface : XPCOMUtils.generateQI([Ci.fuelIApplication, Ci.extIApplication, Ci.nsIObserver, Ci.nsIClassInfo]),
  693.  
  694.   getInterfaces : function app_gi(aCount) {
  695.     var interfaces = [Ci.fuelIApplication, Ci.extIApplication, Ci.nsIObserver, Ci.nsIClassInfo];
  696.     aCount.value = interfaces.length;
  697.     return interfaces;
  698.   },
  699.  
  700.   // for nsIObserver
  701.   observe: function app_observe(aSubject, aTopic, aData) {
  702.     // Call the extApplication version of this function first
  703.     this.__proto__.__proto__.observe.call(this, aSubject, aTopic, aData);
  704.     if (aTopic == "xpcom-shutdown") {
  705.       this._bookmarks = null;
  706.       Utilities.free();
  707.     }
  708.   },
  709.  
  710.   get bookmarks() {
  711.     if (this._bookmarks == null)
  712.       this._bookmarks = new BookmarkRoots();
  713.  
  714.     return this._bookmarks;
  715.   },
  716.  
  717.   get windows() {
  718.     var win = [];
  719.     var enum = Utilities.windowMediator.getEnumerator("navigator:browser");
  720.  
  721.     while (enum.hasMoreElements())
  722.       win.push(new Window(enum.getNext()));
  723.  
  724.     return win;
  725.   },
  726.  
  727.   get activeWindow() {
  728.     return new Window(Utilities.windowMediator.getMostRecentWindow("navigator:browser"));
  729.   }
  730. };
  731.  
  732. //module initialization
  733. function NSGetModule(aCompMgr, aFileSpec) {
  734.   // set the proto, defined in extApplication.js
  735.   Application.prototype.__proto__ = extApplication.prototype;
  736.   return XPCOMUtils.generateModule([Application]);
  737. }
  738.  
  739. /* ***** BEGIN LICENSE BLOCK *****
  740.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  741.  *
  742.  * The contents of this file are subject to the Mozilla Public License Version
  743.  * 1.1 (the "License"); you may not use this file except in compliance with
  744.  * the License. You may obtain a copy of the License at
  745.  * http://www.mozilla.org/MPL/
  746.  *
  747.  * Software distributed under the License is distributed on an "AS IS" basis,
  748.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  749.  * for the specific language governing rights and limitations under the
  750.  * License.
  751.  *
  752.  * The Original Code is FUEL.
  753.  *
  754.  * The Initial Developer of the Original Code is Mozilla Corporation.
  755.  * Portions created by the Initial Developer are Copyright (C) 2006
  756.  * the Initial Developer. All Rights Reserved.
  757.  *
  758.  * Contributor(s):
  759.  *  Mark Finkle <mfinkle@mozilla.com> (Original Author)
  760.  *  John Resig  <jresig@mozilla.com> (Original Author)
  761.  *
  762.  * Alternatively, the contents of this file may be used under the terms of
  763.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  764.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  765.  * in which case the provisions of the GPL or the LGPL are applicable instead
  766.  * of those above. If you wish to allow use of your version of this file only
  767.  * under the terms of either the GPL or the LGPL, and not to allow others to
  768.  * use your version of this file under the terms of the MPL, indicate your
  769.  * decision by deleting the provisions above and replace them with the notice
  770.  * and other provisions required by the GPL or the LGPL. If you do not delete
  771.  * the provisions above, a recipient may use your version of this file under
  772.  * the terms of any one of the MPL, the GPL or the LGPL.
  773.  *
  774.  * ***** END LICENSE BLOCK ***** */
  775.  
  776. //=================================================
  777. // Shutdown - used to store cleanup functions which will
  778. //            be called on Application shutdown
  779. var gShutdown = [];
  780.  
  781. //=================================================
  782. // Console constructor
  783. function Console() {
  784.   this._console = Components.classes["@mozilla.org/consoleservice;1"]
  785.     .getService(Ci.nsIConsoleService);
  786. }
  787.  
  788. //=================================================
  789. // Console implementation
  790. Console.prototype = {
  791.   log : function cs_log(aMsg) {
  792.     this._console.logStringMessage(aMsg);
  793.   },
  794.  
  795.   open : function cs_open() {
  796.     var wMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
  797.                               .getService(Ci.nsIWindowMediator);
  798.     var console = wMediator.getMostRecentWindow("global:console");
  799.     if (!console) {
  800.       var wWatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
  801.                              .getService(Ci.nsIWindowWatcher);
  802.       wWatch.openWindow(null, "chrome://global/content/console.xul", "_blank",
  803.                         "chrome,dialog=no,all", null);
  804.     } else {
  805.       // console was already open
  806.       console.focus();
  807.     }
  808.   },
  809.  
  810.   QueryInterface : XPCOMUtils.generateQI([Ci.extIConsole])
  811. };
  812.  
  813.  
  814. //=================================================
  815. // EventItem constructor
  816. function EventItem(aType, aData) {
  817.   this._type = aType;
  818.   this._data = aData;
  819. }
  820.  
  821. //=================================================
  822. // EventItem implementation
  823. EventItem.prototype = {
  824.   _cancel : false,
  825.  
  826.   get type() {
  827.     return this._type;
  828.   },
  829.  
  830.   get data() {
  831.     return this._data;
  832.   },
  833.  
  834.   preventDefault : function ei_pd() {
  835.     this._cancel = true;
  836.   },
  837.  
  838.   QueryInterface : XPCOMUtils.generateQI([Ci.extIEventItem])
  839. };
  840.  
  841.  
  842. //=================================================
  843. // Events constructor
  844. function Events() {
  845.   this._listeners = [];
  846. }
  847.  
  848. //=================================================
  849. // Events implementation
  850. Events.prototype = {
  851.   addListener : function evts_al(aEvent, aListener) {
  852.     if (this._listeners.some(hasFilter))
  853.       return;
  854.  
  855.     this._listeners.push({
  856.       event: aEvent,
  857.       listener: aListener
  858.     });
  859.  
  860.     function hasFilter(element) {
  861.       return element.event == aEvent && element.listener == aListener;
  862.     }
  863.   },
  864.  
  865.   removeListener : function evts_rl(aEvent, aListener) {
  866.     this._listeners = this._listeners.filter(hasFilter);
  867.  
  868.     function hasFilter(element) {
  869.       return element.event != aEvent && element.listener != aListener;
  870.     }
  871.   },
  872.  
  873.   dispatch : function evts_dispatch(aEvent, aEventItem) {
  874.     eventItem = new EventItem(aEvent, aEventItem);
  875.  
  876.     this._listeners.forEach(function(key){
  877.       if (key.event == aEvent) {
  878.         key.listener.handleEvent ?
  879.           key.listener.handleEvent(eventItem) :
  880.           key.listener(eventItem);
  881.       }
  882.     });
  883.  
  884.     return !eventItem._cancel;
  885.   },
  886.  
  887.   QueryInterface : XPCOMUtils.generateQI([Ci.extIEvents])
  888. };
  889.  
  890.  
  891. //=================================================
  892. // PreferenceBranch constructor
  893. function PreferenceBranch(aBranch) {
  894.   if (!aBranch)
  895.     aBranch = "";
  896.  
  897.   this._root = aBranch;
  898.   this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
  899.                           .getService(Ci.nsIPrefService);
  900.  
  901.   if (aBranch)
  902.     this._prefs = this._prefs.getBranch(aBranch);
  903.  
  904.   this._prefs.QueryInterface(Ci.nsIPrefBranch);
  905.   this._prefs.QueryInterface(Ci.nsIPrefBranch2);
  906.  
  907.   // we want to listen to "all" changes for this branch, so pass in a blank domain
  908.   this._prefs.addObserver("", this, true);
  909.   this._events = new Events();
  910.  
  911.   var self = this;
  912.   gShutdown.push(function() { self._shutdown(); });
  913. }
  914.  
  915. //=================================================
  916. // PreferenceBranch implementation
  917. PreferenceBranch.prototype = {
  918.   // cleanup observer so we don't leak
  919.   _shutdown: function prefs_shutdown() {
  920.     this._prefs.removeObserver(this._root, this);
  921.  
  922.     this._prefs = null;
  923.     this._events = null;
  924.   },
  925.  
  926.   // for nsIObserver
  927.   observe: function prefs_observe(aSubject, aTopic, aData) {
  928.     if (aTopic == "nsPref:changed")
  929.       this._events.dispatch("change", aData);
  930.   },
  931.  
  932.   get root() {
  933.     return this._root;
  934.   },
  935.  
  936.   get all() {
  937.     return this.find({});
  938.   },
  939.  
  940.   get events() {
  941.     return this._events;
  942.   },
  943.  
  944.   // XXX: Disabled until we can figure out the wrapped object issues
  945.   // name: "name" or /name/
  946.   // path: "foo.bar." or "" or /fo+\.bar/
  947.   // type: Boolean, Number, String (getPrefType)
  948.   // locked: true, false (prefIsLocked)
  949.   // modified: true, false (prefHasUserValue)
  950.   find : function prefs_find(aOptions) {
  951.     var retVal = [];
  952.     var items = this._prefs.getChildList("", []);
  953.  
  954.     for (var i = 0; i < items.length; i++) {
  955.       retVal.push(new Preference(items[i], this));
  956.     }
  957.  
  958.     return retVal;
  959.   },
  960.  
  961.   has : function prefs_has(aName) {
  962.     return (this._prefs.getPrefType(aName) != Ci.nsIPrefBranch.PREF_INVALID);
  963.   },
  964.  
  965.   get : function prefs_get(aName) {
  966.     return this.has(aName) ? new Preference(aName, this) : null;
  967.   },
  968.  
  969.   getValue : function prefs_gv(aName, aValue) {
  970.     var type = this._prefs.getPrefType(aName);
  971.  
  972.     switch (type) {
  973.       case Ci.nsIPrefBranch2.PREF_STRING:
  974.         aValue = this._prefs.getComplexValue(aName, Ci.nsISupportsString).data;
  975.         break;
  976.       case Ci.nsIPrefBranch2.PREF_BOOL:
  977.         aValue = this._prefs.getBoolPref(aName);
  978.         break;
  979.       case Ci.nsIPrefBranch2.PREF_INT:
  980.         aValue = this._prefs.getIntPref(aName);
  981.         break;
  982.     }
  983.  
  984.     return aValue;
  985.   },
  986.  
  987.   setValue : function prefs_sv(aName, aValue) {
  988.     var type = aValue != null ? aValue.constructor.name : "";
  989.  
  990.     switch (type) {
  991.       case "String":
  992.         var str = Components.classes["@mozilla.org/supports-string;1"]
  993.                             .createInstance(Ci.nsISupportsString);
  994.         str.data = aValue;
  995.         this._prefs.setComplexValue(aName, Ci.nsISupportsString, str);
  996.         break;
  997.       case "Boolean":
  998.         this._prefs.setBoolPref(aName, aValue);
  999.         break;
  1000.       case "Number":
  1001.         this._prefs.setIntPref(aName, aValue);
  1002.         break;
  1003.       default:
  1004.         throw("Unknown preference value specified.");
  1005.     }
  1006.   },
  1007.  
  1008.   reset : function prefs_reset() {
  1009.     this._prefs.resetBranch("");
  1010.   },
  1011.  
  1012.   QueryInterface : XPCOMUtils.generateQI([Ci.extIPreferenceBranch, Ci.nsISupportsWeakReference])
  1013. };
  1014.  
  1015.  
  1016. //=================================================
  1017. // Preference constructor
  1018. function Preference(aName, aBranch) {
  1019.   this._name = aName;
  1020.   this._branch = aBranch;
  1021.   this._events = new Events();
  1022.  
  1023.   var self = this;
  1024.  
  1025.   this.branch.events.addListener("change", function(aEvent){
  1026.     if (aEvent.data == self.name)
  1027.       self.events.dispatch(aEvent.type, aEvent.data);
  1028.   });
  1029. }
  1030.  
  1031. //=================================================
  1032. // Preference implementation
  1033. Preference.prototype = {
  1034.   get name() {
  1035.     return this._name;
  1036.   },
  1037.  
  1038.   get type() {
  1039.     var value = "";
  1040.     var type = this.branch._prefs.getPrefType(this._name);
  1041.  
  1042.     switch (type) {
  1043.       case Ci.nsIPrefBranch2.PREF_STRING:
  1044.         value = "String";
  1045.         break;
  1046.       case Ci.nsIPrefBranch2.PREF_BOOL:
  1047.         value = "Boolean";
  1048.         break;
  1049.       case Ci.nsIPrefBranch2.PREF_INT:
  1050.         value = "Number";
  1051.         break;
  1052.     }
  1053.  
  1054.     return value;
  1055.   },
  1056.  
  1057.   get value() {
  1058.     return this.branch.getValue(this._name, null);
  1059.   },
  1060.  
  1061.   set value(aValue) {
  1062.     return this.branch.setValue(this._name, aValue);
  1063.   },
  1064.  
  1065.   get locked() {
  1066.     return this.branch._prefs.prefIsLocked(this.name);
  1067.   },
  1068.  
  1069.   set locked(aValue) {
  1070.     this.branch._prefs[ aValue ? "lockPref" : "unlockPref" ](this.name);
  1071.   },
  1072.  
  1073.   get modified() {
  1074.     return this.branch._prefs.prefHasUserValue(this.name);
  1075.   },
  1076.  
  1077.   get branch() {
  1078.     return this._branch;
  1079.   },
  1080.  
  1081.   get events() {
  1082.     return this._events;
  1083.   },
  1084.  
  1085.   reset : function pref_reset() {
  1086.     this.branch._prefs.clearUserPref(this.name);
  1087.   },
  1088.  
  1089.   QueryInterface : XPCOMUtils.generateQI([Ci.extIPreference])
  1090. };
  1091.  
  1092.  
  1093. //=================================================
  1094. // SessionStorage constructor
  1095. function SessionStorage() {
  1096.   this._storage = {};
  1097.   this._events = new Events();
  1098. }
  1099.  
  1100. //=================================================
  1101. // SessionStorage implementation
  1102. SessionStorage.prototype = {
  1103.   get events() {
  1104.     return this._events;
  1105.   },
  1106.  
  1107.   has : function ss_has(aName) {
  1108.     return this._storage.hasOwnProperty(aName);
  1109.   },
  1110.  
  1111.   set : function ss_set(aName, aValue) {
  1112.     this._storage[aName] = aValue;
  1113.     this._events.dispatch("change", aName);
  1114.   },
  1115.  
  1116.   get : function ss_get(aName, aDefaultValue) {
  1117.     return this.has(aName) ? this._storage[aName] : aDefaultValue;
  1118.   },
  1119.  
  1120.   QueryInterface : XPCOMUtils.generateQI([Ci.extISessionStorage])
  1121. };
  1122.  
  1123.  
  1124. //=================================================
  1125. // Extension constructor
  1126. function Extension(aItem) {
  1127.   this._item = aItem;
  1128.   this._firstRun = false;
  1129.   this._prefs = new PreferenceBranch("extensions." + this._item.id + ".");
  1130.   this._storage = new SessionStorage();
  1131.   this._events = new Events();
  1132.  
  1133.   var installPref = "install-event-fired";
  1134.   if (!this._prefs.has(installPref)) {
  1135.     this._prefs.setValue(installPref, true);
  1136.     this._firstRun = true;
  1137.   }
  1138.  
  1139.   this._enabled = false;
  1140.   const PREFIX_ITEM_URI = "urn:mozilla:item:";
  1141.   const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
  1142.   var rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
  1143.   var itemResource = rdf.GetResource(PREFIX_ITEM_URI + this._item.id);
  1144.   if (itemResource) {
  1145.     var extmgr = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);
  1146.     var ds = extmgr.datasource;
  1147.     var target = ds.GetTarget(itemResource, rdf.GetResource(PREFIX_NS_EM + "isDisabled"), true);
  1148.     if (target && target instanceof Ci.nsIRDFLiteral)
  1149.       this._enabled = (target.Value != "true");
  1150.   }
  1151.  
  1152.   var os = Components.classes["@mozilla.org/observer-service;1"]
  1153.                      .getService(Ci.nsIObserverService);
  1154.   os.addObserver(this, "em-action-requested", false);
  1155.  
  1156.   var self = this;
  1157.   gShutdown.push(function(){ self._shutdown(); });
  1158. }
  1159.  
  1160. //=================================================
  1161. // Extension implementation
  1162. Extension.prototype = {
  1163.   // cleanup observer so we don't leak
  1164.   _shutdown: function ext_shutdown() {
  1165.     var os = Components.classes["@mozilla.org/observer-service;1"]
  1166.                        .getService(Ci.nsIObserverService);
  1167.     os.removeObserver(this, "em-action-requested");
  1168.  
  1169.     this._prefs = null;
  1170.     this._storage = null;
  1171.     this._events = null;
  1172.   },
  1173.  
  1174.   // for nsIObserver
  1175.   observe: function ext_observe(aSubject, aTopic, aData)
  1176.   {
  1177.     if ((aSubject instanceof Ci.nsIUpdateItem) && (aSubject.id == this._item.id))
  1178.     {
  1179.       if (aData == "item-uninstalled")
  1180.         this._events.dispatch("uninstall", this._item.id);
  1181.       else if (aData == "item-disabled")
  1182.         this._events.dispatch("disable", this._item.id);
  1183.       else if (aData == "item-enabled")
  1184.         this._events.dispatch("enable", this._item.id);
  1185.       else if (aData == "item-cancel-action")
  1186.         this._events.dispatch("cancel", this._item.id);
  1187.       else if (aData == "item-upgraded")
  1188.         this._events.dispatch("upgrade", this._item.id);
  1189.     }
  1190.   },
  1191.  
  1192.   get id() {
  1193.     return this._item.id;
  1194.   },
  1195.  
  1196.   get name() {
  1197.     return this._item.name;
  1198.   },
  1199.  
  1200.   get enabled() {
  1201.     return this._enabled;
  1202.   },
  1203.  
  1204.   get version() {
  1205.     return this._item.version;
  1206.   },
  1207.  
  1208.   get firstRun() {
  1209.     return this._firstRun;
  1210.   },
  1211.  
  1212.   get storage() {
  1213.     return this._storage;
  1214.   },
  1215.  
  1216.   get prefs() {
  1217.     return this._prefs;
  1218.   },
  1219.  
  1220.   get events() {
  1221.     return this._events;
  1222.   },
  1223.  
  1224.   QueryInterface : XPCOMUtils.generateQI([Ci.extIExtension])
  1225. };
  1226.  
  1227.  
  1228. //=================================================
  1229. // Extensions constructor
  1230. function Extensions() {
  1231.   this._extmgr = Components.classes["@mozilla.org/extensions/manager;1"]
  1232.                            .getService(Ci.nsIExtensionManager);
  1233.  
  1234.   this._cache = {};
  1235.  
  1236.   var self = this;
  1237.   gShutdown.push(function() { self._shutdown(); });
  1238. }
  1239.  
  1240. //=================================================
  1241. // Extensions implementation
  1242. Extensions.prototype = {
  1243.   _shutdown : function exts_shutdown() {
  1244.     this._extmgr = null;
  1245.     this._cache = null;
  1246.   },
  1247.  
  1248.   /*
  1249.    * Helper method to check cache before creating a new extension
  1250.    */
  1251.   _get : function exts_get(aId) {
  1252.     if (this._cache.hasOwnProperty(aId))
  1253.       return this._cache[aId];
  1254.  
  1255.     var newExt = new Extension(this._extmgr.getItemForID(aId));
  1256.     this._cache[aId] = newExt;
  1257.     return newExt;
  1258.   },
  1259.  
  1260.   get all() {
  1261.     return this.find({});
  1262.   },
  1263.  
  1264.   // XXX: Disabled until we can figure out the wrapped object issues
  1265.   // id: "some@id" or /id/
  1266.   // name: "name" or /name/
  1267.   // version: "1.0.1"
  1268.   // minVersion: "1.0"
  1269.   // maxVersion: "2.0"
  1270.   find : function exts_find(aOptions) {
  1271.     var retVal = [];
  1272.     var items = this._extmgr.getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
  1273.  
  1274.     for (var i = 0; i < items.length; i++) {
  1275.       retVal.push(this._get(items[i].id));
  1276.     }
  1277.  
  1278.     return retVal;
  1279.   },
  1280.  
  1281.   has : function exts_has(aId) {
  1282.     return this._extmgr.getItemForID(aId) != null;
  1283.   },
  1284.  
  1285.   get : function exts_get(aId) {
  1286.     return this.has(aId) ? this._get(aId) : null;
  1287.   },
  1288.  
  1289.   QueryInterface : XPCOMUtils.generateQI([Ci.extIExtensions])
  1290. };
  1291.  
  1292. //=================================================
  1293. // extApplication constructor
  1294. function extApplication() {
  1295. }
  1296.  
  1297. //=================================================
  1298. // extApplication implementation
  1299. extApplication.prototype = {
  1300.   initToolkitHelpers: function extApp_initToolkitHelpers() {
  1301.     this._console = null;
  1302.     this._storage = null;
  1303.     this._prefs = null;
  1304.     this._extensions = null;
  1305.     this._events = null;
  1306.  
  1307.     this._info = Components.classes["@mozilla.org/xre/app-info;1"]
  1308.                            .getService(Ci.nsIXULAppInfo);
  1309.  
  1310.     var os = Components.classes["@mozilla.org/observer-service;1"]
  1311.                        .getService(Ci.nsIObserverService);
  1312.  
  1313.     os.addObserver(this, "final-ui-startup", false);
  1314.     os.addObserver(this, "quit-application-requested", false);
  1315.     os.addObserver(this, "xpcom-shutdown", false);
  1316.   },
  1317.  
  1318.   // get this contractID registered for certain categories via XPCOMUtils
  1319.   _xpcom_categories: [
  1320.     // make Application a startup observer
  1321.     { category: "app-startup", service: true },
  1322.  
  1323.     // add Application as a global property for easy access
  1324.     { category: "JavaScript global privileged property" }
  1325.   ],
  1326.  
  1327.   // for nsIClassInfo
  1328.   flags : Ci.nsIClassInfo.SINGLETON,
  1329.   implementationLanguage : Ci.nsIProgrammingLanguage.JAVASCRIPT,
  1330.  
  1331.   getInterfaces : function app_gi(aCount) {
  1332.     var interfaces = [Ci.extIApplication, Ci.nsIObserver, Ci.nsIClassInfo];
  1333.     aCount.value = interfaces.length;
  1334.     return interfaces;
  1335.   },
  1336.  
  1337.   getHelperForLanguage : function app_ghfl(aCount) {
  1338.     return null;
  1339.   },
  1340.  
  1341.   // extIApplication
  1342.   get id() {
  1343.     return this._info.ID;
  1344.   },
  1345.  
  1346.   get name() {
  1347.     return this._info.name;
  1348.   },
  1349.  
  1350.   get version() {
  1351.     return this._info.version;
  1352.   },
  1353.  
  1354.   // for nsIObserver
  1355.   observe: function app_observe(aSubject, aTopic, aData) {
  1356.     if (aTopic == "app-startup") {
  1357.       this.events.dispatch("load", "application");
  1358.     }
  1359.     else if (aTopic == "final-ui-startup") {
  1360.       this.events.dispatch("ready", "application");
  1361.     }
  1362.     else if (aTopic == "quit-application-requested") {
  1363.       // we can stop the quit by checking the return value
  1364.       if (this.events.dispatch("quit", "application") == false)
  1365.         aSubject.data = true;
  1366.     }
  1367.     else if (aTopic == "xpcom-shutdown") {
  1368.  
  1369.       this.events.dispatch("unload", "application");
  1370.  
  1371.       // call the cleanup functions and empty the array
  1372.       while (gShutdown.length) {
  1373.         gShutdown.shift()();
  1374.       }
  1375.  
  1376.       // release our observers
  1377.       var os = Components.classes["@mozilla.org/observer-service;1"]
  1378.                          .getService(Ci.nsIObserverService);
  1379.  
  1380.       os.removeObserver(this, "final-ui-startup");
  1381.       os.removeObserver(this, "quit-application-requested");
  1382.       os.removeObserver(this, "xpcom-shutdown");
  1383.  
  1384.       this._info = null;
  1385.       this._console = null;
  1386.       this._prefs = null;
  1387.       this._storage = null;
  1388.       this._events = null;
  1389.       this._extensions = null;
  1390.     }
  1391.   },
  1392.  
  1393.   get console() {
  1394.     if (this._console == null)
  1395.         this._console = new Console();
  1396.  
  1397.     return this._console;
  1398.   },
  1399.  
  1400.   get storage() {
  1401.     if (this._storage == null)
  1402.         this._storage = new SessionStorage();
  1403.  
  1404.     return this._storage;
  1405.   },
  1406.  
  1407.   get prefs() {
  1408.     if (this._prefs == null)
  1409.         this._prefs = new PreferenceBranch("");
  1410.  
  1411.     return this._prefs;
  1412.   },
  1413.  
  1414.   get extensions() {
  1415.     if (this._extensions == null)
  1416.       this._extensions = new Extensions();
  1417.  
  1418.     return this._extensions;
  1419.   },
  1420.  
  1421.   get events() {
  1422.     if (this._events == null)
  1423.         this._events = new Events();
  1424.  
  1425.     return this._events;
  1426.   },
  1427.  
  1428.   // helper method for correct quitting/restarting
  1429.   _quitWithFlags: function app__quitWithFlags(aFlags) {
  1430.     let os = Components.classes["@mozilla.org/observer-service;1"]
  1431.                        .getService(Components.interfaces.nsIObserverService);
  1432.     let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
  1433.                                .createInstance(Components.interfaces.nsISupportsPRBool);
  1434.     os.notifyObservers(cancelQuit, "quit-application-requested", null);
  1435.     if (cancelQuit.data)
  1436.       return false; // somebody canceled our quit request
  1437.     
  1438.     let appStartup = Components.classes['@mozilla.org/toolkit/app-startup;1']
  1439.                                .getService(Components.interfaces.nsIAppStartup);
  1440.     appStartup.quit(aFlags);
  1441.     return true;
  1442.   },
  1443.  
  1444.   quit: function app_quit() {
  1445.     return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit);
  1446.   },
  1447.  
  1448.   restart: function app_restart() {
  1449.     return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit |
  1450.                                Components.interfaces.nsIAppStartup.eRestart);
  1451.   },
  1452.  
  1453.   QueryInterface : XPCOMUtils.generateQI([Ci.extIApplication, Ci.nsISupportsWeakReference])
  1454. };
  1455.